﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using lib.Twitter;

namespace lib.JsonParser
{
    // Convert json object format to twitter objects!
    public class JsonTwitter
    {
        ///
        // Convert a json object format to a list of User 
        // and Status objects.
        //
        // TODO : Let the function figure out the base class!
        //        maybe look at some attributes of the object and
        //        make a decision from that.
        //
        // Twitter function  - BaseClass to parse with
        // =============================================
        // getFriendStatus   - "Status"
        // getUserStatus     - "Status"
        // getPublicTimeline - "Status"
        // getFriends        - "User"
        //
        static public List<Object> jsonToTwitter(Object json, String baseType)
        {
            List<Object> olist = new List<object>();
            if (json is JsonObject)
            {
                if (baseType.Equals("User"))
                    olist = jsonObjectToUser((JsonObject)json);
                else if (baseType.Equals("Status"))
                    olist = jsonObjectToStatus((JsonObject)json);
                else
                    throw new lib.CustomExceptions.JsonTwitterError("Wrong base class");
            }
            else if (json is JsonArray)
            {
                olist = jsonArrayToObject((JsonArray)json, baseType);
            }
            else
            {
                throw new lib.CustomExceptions.JsonTwitterError("Object not in a json object format");
            }

            return olist;
        }

        static private List<Object> jsonArrayToObject(JsonArray array, String baseType)
        {
            //Console.WriteLine("ARRAY START");
            List<Object> olist = new List<Object>();

            foreach (Object jo in array)
            {
                if (jo is JsonObject)
                {
                    List<Object> olist2;
                    if (baseType.Equals("User"))
                    {
                        olist2 = jsonObjectToUser((JsonObject)jo);
                    }
                    else if (baseType.Equals("Status"))
                    {
                        olist2 = jsonObjectToStatus((JsonObject)jo);
                    }
                    else
                    {
                        throw new lib.CustomExceptions.JsonTwitterError("Wrong base class");
                    }
                    foreach (Object o in olist2)
                    {
                        olist.Add(o);
                    }
                }
                else
                {
                    throw new lib.CustomExceptions.JsonTwitterError("Object not in a json object format");
                }
            }
            //Console.WriteLine("ARRAY END");
            return olist;
        }

        static private List<Object> jsonObjectToUser(JsonObject jsonObject)
        {
            List<Object> olist = new List<Object>();
            User newUser = new User();
            foreach (var pair in jsonObject)
            {
                switch (pair.Key)
                {
                    case "created_at":
                        newUser.created_at = getDateTime((String)pair.Value);
                        break;
                    case "description":
                        if (pair.Value != null)
                            newUser.description = (String)pair.Value;
                        else
                            newUser.description = "";
                        break;
                    case "favourites_count":
                        if (pair.Value != null)
                            newUser.favourites_count = (int)(double)pair.Value;
                        else
                            newUser.favourites_count = 0;
                        break;
                    case "followers_count":
                        if (pair.Value != null)
                            newUser.followers_count = (int)(double)pair.Value;
                        else
                            newUser.followers_count = 0;
                        break;
                    case "friends_count":
                        if (pair.Value != null)
                            newUser.friends_count = (int)(double)pair.Value;
                        else
                            newUser.friends_count = 0;
                        break;
                    case "id":
                        newUser.id = (long)(double)pair.Value;
                        break;
                    case "location":
                        if (pair.Value != null)
                            newUser.location = (String)pair.Value;
                        else
                            newUser.location = "";
                        break;
                    case "name":
                        if (pair.Value != null)
                            newUser.name = (String)pair.Value;
                        else
                            newUser.name = "";
                        break;
                    case "profile_image_url":
                        if (pair.Value != null)
                            newUser.profile_image_url = (String)pair.Value;
                        else
                            newUser.profile_image_url = "";
                        break;
                    case "screen_name":
                        if (pair.Value != null)
                            newUser.screen_name = (String)pair.Value;
                        else
                            newUser.screen_name = "";
                        break;
                    case "statuses_count":
                        if (pair.Value != null)
                            newUser.statuses_count = (int)(double)pair.Value;
                        else
                            newUser.statuses_count = 0;
                        break;
                    case "url":
                        if (pair.Value != null)
                            newUser.url = (String)pair.Value;
                        else
                            newUser.url = "";
                        break;
                    case "status":
                        // parse status object!
                        olist.Add(jsonObjectToStatus((JsonObject)pair.Value));
                        break;
                }
            }
            olist.Add(newUser);
            return olist;
        }

        static private List<Object> jsonObjectToStatus(JsonObject jsonObject)
        {
            List<Object> olist = new List<Object>();
            Status newStatus = new Status();
            foreach (var pair in jsonObject)
            {
                switch (pair.Key)
                {
                    case "created_at":
                        newStatus.created_at = getDateTime((String)pair.Value); ;
                        break;
                    case "id":
                        newStatus.id = (long)(double)pair.Value;
                        break;
                    case "in_reply_to_screen_name":
                        if (pair.Value != null)
                            newStatus.in_reply_to_screen_name = (String)pair.Value;
                        else
                            newStatus.in_reply_to_screen_name = "";
                        break;
                    case "in_reply_to_status_id":
                        if (pair.Value != null)
                            newStatus.in_reply_to_status_id = (int)(double)pair.Value;
                        else
                            newStatus.in_reply_to_status_id = -1;
                        break;
                    case "in_reply_to_user_id":
                        if (pair.Value != null)
                            newStatus.in_reply_to_user_id = (int)(double)pair.Value;
                        else
                            newStatus.in_reply_to_user_id = -1;
                        break;
                    case "source":
                        if (pair.Value != null)
                            newStatus.source = (String)pair.Value;
                        else
                            newStatus.source = "";
                        break;
                    case "text":
                        if (pair.Value != null)
                            newStatus.text = (String)pair.Value;
                        else
                            newStatus.text = "";
                        break;
                    case "user":
                        // There should only be one object in this list!
                        List<Object> list = jsonObjectToUser((JsonObject)pair.Value);
                        foreach (Object o in list)
                        {
                            newStatus.user_id = ((User)o).id;
                            olist.Add(o);
                        }
                        break;
                }
            }
            olist.Add(newStatus);
            return olist;
        }

        // Parse the time string from Twitter to DateTime
        static private DateTime getDateTime(String datetime)
        {
            // "Fri Aug 01 19:42:20 +0000 2008"
 
            int day;
            int month;
            int year;
            int sec;
            int min;
            int hour;
            
            if (!int.TryParse(datetime.Substring(8, 2), out day))
                throw new lib.CustomExceptions.JsonTwitterError("Failed to parse time string to DateTime");

            if(!int.TryParse(datetime.Substring(26, 4), out year))
                throw new lib.CustomExceptions.JsonTwitterError("Failed to parse time string to DateTime");

            if(!int.TryParse(datetime.Substring(11, 2), out hour))
                throw new lib.CustomExceptions.JsonTwitterError("Failed to parse time string to DateTime");

            if(!int.TryParse(datetime.Substring(14, 2), out min))
                throw new lib.CustomExceptions.JsonTwitterError("Failed to parse time string to DateTime");

            if(!int.TryParse(datetime.Substring(17, 2), out sec))
                throw new lib.CustomExceptions.JsonTwitterError("Failed to parse time string to DateTime");


            // get month number
            switch (datetime.Substring(4, 3))
            {
                case "Jan":
                    month = 1;
                    break;
                case "Feb":
                    month = 2;
                    break;
                case "Mar":
                    month = 3;
                    break;
                case "Apr":
                    month = 4;
                    break;
                case "May":
                    month = 5;
                    break;
                case "Jun":
                    month = 6;
                    break;
                case "Jul":
                    month = 7;
                    break;
                case "Aug":
                    month = 8;
                    break;
                case "Sep":
                    month = 9;
                    break;
                case "Oct":
                    month = 10;
                    break;
                case "Nov":
                    month = 11;
                    break;
                case "Dec":
                    month = 12;
                    break;
                default:
                    throw new lib.CustomExceptions.JsonTwitterError("Failed to parse time string to DateTime");
            }
            return new DateTime(year, month, day, hour, min, sec);
        }

    }
}
